/******************************************************************************
 * SVN­Version­Information:
 * ­­­­­­­­­­­­­­­­­­­­­­­­---------------------
 * $LastChangedRevision: 6 $
 * $LastChangedBy: c.a.duevel $
 * $LastChangedDate: 2009-08-26 15:12:37 +0000 (Wed, 26 Aug 2009) $
 * $HeadURL: http://robofight.googlecode.com/svn/trunk/Server/src/de/hft_stuttgart/botwar/server/model/GameMap.java $
 ******************************************************************************/
package de.hft_stuttgart.botwar.server.model;

import de.hft_stuttgart.botwar.common.models.MapInfo;
import de.hft_stuttgart.botwar.common.models.Position;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.log4j.Logger;

/**
 * Instance of this class represents a map.
 * Named GameMap to avoid confusion with
 * <code>java.util.Map</code>
 * @author c.a.duevel@gmail.com
 */
public class GameMap {

    public static HashMap<String, GameMap> allMaps = new HashMap<String, GameMap>();
    public static HashMap<String, MapInfo> allMapInfos = new HashMap<String, MapInfo>();
    public final String name;
    public final Logger LOGGER = Logger.getLogger(GameMap.class);
    static final int HEIGHT = (int) (Position.Y_MAX / 10);
    static final int WIDTH = (int) (Position.X_MAX / 10);
    static final char STARTPOINT = 'b';
    static final char NONE = 'c';
    static final char BLOCKED = 'a';

    /**
     * Represents a field on the map
     */
    public enum Field {

        BLOCKED, STARTPOINT, NONE
    }
    private Field fields[][];
    private List<Position> startPoints;
    private List<Position> blockedPoints;

    /**
     * Creates a new map.
     * @param name The name of this map.
     * @param fields The fields of this map.
     */
    public GameMap(final String name, final Field[][] fields) {
        assert fields.length == HEIGHT;
        this.name = name;
        this.fields = fields;

        startPoints = new ArrayList<Position>();
        blockedPoints = new ArrayList<Position>();
        for (int width = 0; width < WIDTH; width++) {
            for (int height = 0; height < HEIGHT; height++) {
                if (fields[height][width].equals(Field.STARTPOINT)) {
                    startPoints.add(new Position(width * 10 + 5, height * 10 + 5));
                } else if (fields[height][width].equals(Field.BLOCKED)) {
                    blockedPoints.add(new Position(width * 10 + 5, height * 10 + 5));
                } else {
                    continue;
                }
            }
        }

    }

    /**
     *
     * @return An info object containing the name and the maximum number of
     * bots for this map.
     */
    public MapInfo getInfo() {
        return new MapInfo(name, getStartPoints().size());
    }

    /**
     * 
     * @return The maximum number of bots for this map.
     */
    public int getMaxBots() {
        return getStartPoints().size();

    }

    /**
     * @return List of all start points on a map.
     *
     */
    public List<Position> getStartPoints() {
        return startPoints;
}

    static GameMap createMap(String name, String array[]) {
        Field[][] fields = new Field[HEIGHT][WIDTH];
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < WIDTH; j++) {
                switch (array[i].charAt(j)) {
                    case NONE:
                        fields[i][j] = Field.NONE;
                        break;
                    case BLOCKED:
                        fields[i][j] = Field.BLOCKED;
                        break;
                    case STARTPOINT:
                        fields[i][j] = Field.STARTPOINT;
                        break;
                    default:
                        throw new RuntimeException(String.format("Illegal format" +
                                " in map %s.", name));
                }
            }
        }
        return new GameMap(name, fields);

    }

    /**
     * Creates an instance of this class out of a map file.
     * @param mapFile The map file to construct a GameMap of.
     * @return The constructed GameMap instance.
     * @throws java.io.FileNotFoundException
     * @throws java.io.IOException
     */
    public static GameMap createMapFromFile(File mapFile) throws
            FileNotFoundException, IOException {
        BufferedReader reader = new BufferedReader(new FileReader(mapFile));
        String[] array = readMapFile(reader, mapFile);
        reader.close();
        return createMap(getMapName(mapFile), array);
    }

    static String getMapName(File mapFile) {
        return mapFile.getName().substring(0, mapFile.getName().indexOf("."));
    }

    static String[] readMapFile(BufferedReader reader, File mapFile) throws IOException {

        int lineNumber = 0;
        String array[] = new String[HEIGHT];
        String line = reader.readLine();
        while (line != null) {
            assert line.length() == WIDTH : String.format("File %s has irregular line" +
                    " length in line %d", mapFile.getAbsolutePath(), lineNumber);
            array[lineNumber] = line;
            lineNumber++;
            line = reader.readLine();

            assert lineNumber <= HEIGHT : String.format("File %s has too many lines",
                    mapFile.getAbsolutePath());
        }
        assert lineNumber == HEIGHT : String.format("File %s has too few lines",
                mapFile.getAbsolutePath());
        return array;
    }

}
